package com.shelpe.services.algorithm.controller;

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.async.DeferredResult;

import com.shelpe.services.algorithm.autoDrive.AutoDriveSustainRule;
import com.shelpe.services.algorithm.autoDrive.AutoDriveSustainer;
import com.shelpe.services.algorithm.client.SimbaProxyBaseDto;
import com.shelpe.services.algorithm.client.SinbadClient;
import com.shelpe.services.algorithm.entity.batis.KeywordExample;
import com.shelpe.services.algorithm.entity.jpa.Adgroup;
import com.shelpe.services.algorithm.entity.jpa.AutoProductQueue;
import com.shelpe.services.algorithm.repository.batis.KeywordMapper;
import com.shelpe.services.algorithm.repository.jpa.AdgroupRepository;
import com.shelpe.services.algorithm.repository.jpa.AutoProductQueueRepository;
import com.shelpe.services.algorithm.service.AutoProductQueueService;
import com.shelpe.services.algorithm.sustain.SustainRule;

import lombok.extern.slf4j.Slf4j;


@Controller
@Slf4j
public class AutoProductQueueController implements AutoProductQueueClient {

	@Autowired
	private AutoProductQueueRepository autoProductQueueRepository;
	@Autowired
	private AutoProductQueueService autoProductQueueService;
	@Autowired
	private AutoDriveSustainRule autoDriveSustainRule;
	@Autowired
	private AdgroupRepository adgroupRepository;
	@Autowired
	private KeywordMapper keywordMapper;
	
	@Override
	@ResponseBody
	public DeferredResult<SinbadClient.AdgroupDto> startAutoDrive(@RequestParam("campaign_id") final long campaignID,
			@RequestParam("product_id") final long productID) {
		log.info("begin startAutoDrive {} {}", campaignID, productID);
		SinbadClient.AdgroupDto timeoutRet = new SinbadClient.AdgroupDto();
		timeoutRet.setError(new SimbaProxyBaseDto.Error());
		timeoutRet.getError().setCode(500);
		timeoutRet.getError().setMessage("timeout");
		timeoutRet.getError().setSubCode("timeout");
		timeoutRet.getError().setSubMessage("超时");
		final DeferredResult<SinbadClient.AdgroupDto> result = new DeferredResult<SinbadClient.AdgroupDto>(20 * 1000L, timeoutRet);
		result.onTimeout(new Runnable(){
			@Override
			public void run() {
				log.error("timeout startAutoDrive {} {}", campaignID, productID);
			}
		});
		
		AutoDrivingDto dto = new AutoDrivingDto();
		dto.setCampaignID(campaignID);
		dto.setProductID(productID);
		
		AutoProductQueue.QueuePK pk = new AutoProductQueue.QueuePK();
		pk.setCampaignID(dto.getCampaignID());
		pk.setProductID(dto.getProductID());
		AutoProductQueue queue = this.autoProductQueueRepository.findOne(pk);
		Assert.notNull(queue, "auto_product_queue_not_found");
		
		dto.setDefaultPrice(queue.getDefaultPrice());
		this.autoProductQueueService.autoDrive(result, queue, dto.getDefaultPrice());
		
		return result;
	}

	@Override
	@ResponseBody
	public DeferredResult<AutoDrivingDto> supplementInsight(@RequestParam("campaign_id")final long campaignID,
			@RequestParam("product_id")final long productID) {
		log.info("begin supplementInsight {} {}", campaignID, productID);
		AutoDrivingDto timeoutRet = new AutoDrivingDto();
		timeoutRet.setSuccess(false);
		timeoutRet.setMessage("timeout");
		final DeferredResult<AutoDrivingDto> result = new DeferredResult<AutoDrivingDto>(20 * 1000L, timeoutRet);
		result.onTimeout(new Runnable(){
			@Override
			public void run() {
				log.error("timeout supplementInsight {} {}", campaignID, productID);
			}
		});
		
		AutoDrivingDto dto = new AutoDrivingDto();
		dto.setCampaignID(campaignID);
		dto.setProductID(productID);
		
		AutoProductQueue.QueuePK pk = new AutoProductQueue.QueuePK();
		pk.setCampaignID(dto.getCampaignID());
		pk.setProductID(dto.getProductID());
		AutoProductQueue queue = this.autoProductQueueRepository.findOne(pk);
		if(queue == null){
			dto.setSuccess(false);
			dto.setMessage("queue_not_found");
			result.setResult(dto);
			return result;
		}
		dto.setDefaultPrice(queue.getDefaultPrice());
		dto.setAdgroupID(queue.getAdgroupID());
		
		Adgroup adgroup = this.adgroupRepository.findOne(queue.getAdgroupID());
		if(adgroup == null){
			dto.setSuccess(false);
			dto.setMessage("adgroup_not_found");
			result.setResult(dto);
			return result;
		}
		
		if(adgroup.getDriveType() != 2){
			dto.setSuccess(false);
			dto.setMessage("not_mobile_qscore");
			result.setResult(dto);
			return result;
		}
		
		KeywordExample example = new KeywordExample();
		example.setUserId(adgroup.getUserID());
		example.createCriteria().andAdgroupIdEqualTo(adgroup.getAdgroupID());
		int count = this.keywordMapper.countByExample(example);
		if(count > 0){
			dto.setSuccess(false);
			dto.setMessage("keyword_has_added");
			result.setResult(dto);
			return result;
		}
		
		this.autoProductQueueService.supplementInsight(result, queue, adgroup);
		
		return result;
	}
	
	@Override
	@ResponseBody
	public AutoDrivingDto startChooseWords(@RequestParam("campaign_id") long campaignID,
			@RequestParam("product_id") long productID) {
		log.info("begin startChooseWords {} {}", campaignID, productID);
		AutoDrivingDto dto = new AutoDrivingDto();
		dto.setCampaignID(campaignID);
		dto.setProductID(productID);
		
		AutoProductQueue.QueuePK pk = new AutoProductQueue.QueuePK();
		pk.setCampaignID(dto.getCampaignID());
		pk.setProductID(dto.getProductID());
		AutoProductQueue queue = this.autoProductQueueRepository.findOne(pk);
		Assert.notNull(queue, "auto_product_queue_not_found");
		dto.setDefaultPrice(queue.getDefaultPrice());
		if(dto.getAdgroupID() == 0){
			dto.setAdgroupID(queue.getAdgroupID());
		}
		
		boolean inprogress = (queue.getStatus() == AutoProductQueue.Status.updating && queue.getProgress() == 20);
		boolean needSupplement = (queue.getStatus() == AutoProductQueue.Status.success && queue.getInitialKeywordCount() == 0);
		if(!inprogress && !needSupplement){
			log.error("queue's status and progress is invalid - inprogress[{}], needSupplement[{}]. {}", inprogress, needSupplement, queue);
			dto.setSuccess(false);
			dto.setMessage("invalid_status");
			return dto;
		}
		
		Adgroup adgroup = this.adgroupRepository.findOne(queue.getAdgroupID());
		if(adgroup != null){
			dto.setDefaultPrice(adgroup.getDefaultPrice());
		}
		
		dto.setDefaultPrice(Math.min(dto.getDefaultPrice(), 5));
		log.debug("try to choose word: {} {}", queue, dto);
		boolean status = this.autoProductQueueService.chooseWord(queue, dto.getDefaultPrice());
		dto.setSuccess(status);
		log.debug("end startChooseWords {} {} result: {}", campaignID, productID, status);
		return dto;
	}

	@Override
	@ResponseBody
	public AutoDrivingDto adjustAdgroup(@RequestParam("adgroup_id") long adgroupID) {
		log.info("begin adjustAdgroup {}", adgroupID);
		AutoDrivingDto dto = new AutoDrivingDto();
		
		Adgroup adgroup = this.adgroupRepository.findOne(adgroupID);
		Assert.notNull(adgroup, "adgroup_not_found");
		
		AutoDriveSustainer sustainer = new AutoDriveSustainer();
		sustainer.setAdgroup(adgroup);
		
		boolean toNext = this.autoDriveSustainRule.check(sustainer);
		if(toNext){
			toNext = this.autoDriveSustainRule.prepare(sustainer);
			if(toNext){
				SustainRule.SustainStatus ss = this.autoDriveSustainRule.sustain(sustainer);
				toNext = this.autoDriveSustainRule.maintain(sustainer, ss);
				if(toNext){
					toNext = this.autoDriveSustainRule.mark(sustainer);
				}
			}
		}
		log.debug("end adjustAdgroup {} resut: {}", toNext);
		dto.setSuccess(toNext);
		dto.setAdgroupID(adgroup.getAdgroupID());
		dto.setProductID(adgroup.getProductID());
		dto.setCampaignID(adgroup.getCampaignID());
		
		return dto;
	}

	/*
	 * author  yechen
	 */
	@Override
	@ResponseBody
	public List<AutoDriveShows> listByUserID(@PathVariable("user_id") long userID) {
		List<AutoProductQueue> autoProductQueues = this.autoProductQueueRepository.findByUserID(userID); //此时拿到了所有的userID集合
		List<AutoDriveShows> shows = new ArrayList<AutoDriveShows>();  //设置接收userID的集合的对象。
		
		for(AutoProductQueue autoProductQueue :autoProductQueues){
			AutoDriveShows show = new AutoDriveShows();
			BeanUtils.copyProperties(autoProductQueue, show);
			
			show.setUserID(autoProductQueue.getUserID());
			show.setAdgroupID(autoProductQueue.getAdgroupID());
			show.setCampaignID(autoProductQueue.getCampaignID());
			show.setProductID(autoProductQueue.getProductID());
			show.setProgress(autoProductQueue.getProgress());
			show.setStatus(autoProductQueue.getStatus().getValue());
			show.setType(autoProductQueue.getType().getValue());
			
			shows.add(show);
		}		
		return shows;
	}
	
}